package no.hib.mod250.chat.server;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import no.hib.mod250.chat.client.model.Model;
import no.hib.mod250.chat.client.service.ChatService;

import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

@SuppressWarnings("serial")
public class ChatServiceImpl extends RemoteServiceServlet implements
		ChatService {

	private static final Logger LOG = Logger.getLogger(ChatServiceImpl.class
			.getName());

	public List<Model.User> users = new ArrayList<Model.User>();
	public List<Model.Message> messages = new ArrayList<Model.Message>();
	public List<Model.Action> actions = new ArrayList<Model.Action>();
	private int messagesCount = 0;

	private ChatService.Result generateResult(long lastUpdate) {
		ChatService.Result result = new ChatService.Result();

		result.setUser(getUser());
//		result.setUsers(users);
		result.setLastUpdated((new Date().getTime())+1);

		int tmp = users.indexOf(result.getUser().getEventObject());
		if (tmp >= 0)
		{
			users.get(tmp).setTimestamp(new Date().getTime());
		}
		
		// Users
		List<Model.User> usersTemp = new ArrayList<Model.User>();
		long now = new Date().getTime();

		for (Model.User user : users) {
			// 10 min
			if (user.getTimestamp() > (now - (10 * 60 * 1000))) {
				usersTemp.add(user);
			}
		}
		result.setUsers(usersTemp);

		// Messages
		Model.MessageList messagesTemp = new Model.MessageList();

		for (int i = messages.size() - 1; i >= Math
				.max(0, messages.size() - 50); i--) {
			if (lastUpdate == 0L
					|| lastUpdate <= messages.get(i).getTimestamp()) {
				messagesTemp.add(0, messages.get(i));
			} else {
				i = 0;
			}
		}

		result.setMessages(messagesTemp);

		// Actions
		if (lastUpdate != 0L) {
			List<Model.Action> actionsTemp = new ArrayList<Model.Action>();

			for (int i = actions.size() - 1; i >= Math.max(0,
					actions.size() - 50); i--) {
				if (lastUpdate == 0L
						|| lastUpdate <= actions.get(i).getTimestamp()) {
					actionsTemp.add(0, actions.get(i));
				} else {
					i = 0;
				}
			}

			result.setActions(actionsTemp);
		}

		return result;
	}

	@Override
	public ChatService.Result doInitialize() {
		Model.UserAdmin userAdmin = getUser();
		Model.User user = userAdmin.getEventObject();
		if (userAdmin != null && userAdmin.isLoggedIn()
				&& !users.contains(user)) {
			users.add(user);
		}

		return generateResult(0L);
	}

	private Model.UserAdmin getUser() {
		UserService userService = UserServiceFactory.getUserService();

		Model.UserAdmin user = new Model.UserAdmin();
		user.setLoggedIn(userService.isUserLoggedIn());
		user.setUrlLogin(userService.createLoginURL("/"));

		if (userService.isUserLoggedIn()) {
			user.setId(userService.getCurrentUser().getUserId());
			user.setEmail(userService.getCurrentUser().getEmail());
			user.setNickname(userService.getCurrentUser().getNickname());
			user.setUrlLogout(userService.createLogoutURL("/"));
			user.setAdmin(userService.isUserAdmin());
		}

		return user;
	}

	@Override
	public ChatService.Result doMessageDelete(long lastUpdate, long id)
			throws UnauthorizedException, IllegalMessageException {
		if (!getUser().isLoggedIn()) {
			throw new UnauthorizedException();
		}

		int i = messages.indexOf(new Model.Message(id));

		if (i < 0) {
			throw new IllegalMessageException();
		}

		messages.remove(i);
		actions.add(new Model.DeleteMessageAction(new Date().getTime(), id));

		return generateResult(lastUpdate);
	}

	@Override
	public ChatService.Result doMessageNew(long lastUpdate, String message)
			throws UnauthorizedException {
		if (!getUser().isLoggedIn()) {
			throw new UnauthorizedException();
		}
		Model.Message msg = new Model.Message();
		msg.setMessage(message);
		msg.setUser(getUser().getEventObject());
		msg.setTimestamp(new Date().getTime());
		msg.setId(messagesCount++);

		messages.add(msg);

		return generateResult(lastUpdate);
	}

	@Override
	public ChatService.Result doMessagesDelete(long lastUpdate)
			throws UnauthorizedException {
		Model.UserAdmin user = getUser();

		// Must be logged in and admin
		if (!user.isLoggedIn() || !user.isAdmin()) {
			throw new UnauthorizedException();
		}

		// Remove messages
		messages.clear();

		// Add delete Messages action
		actions.add(new Model.DeleteMessagesAction(new Date().getTime()));

		return generateResult(lastUpdate);
	}

	@Override
	public ChatService.Result doUpdate(long lastUpdate) {
		Model.UserAdmin userAdmin = getUser();
		Model.User user = userAdmin.getEventObject();
		if (userAdmin != null && userAdmin.isLoggedIn()
				&& !users.contains(user)) {
			users.add(user);
		}

		return generateResult(lastUpdate);
	}

	@Override
	public ChatService.Result doUserAvailable(long lastUpdate) {
		int i = users.indexOf(getUser().getEventObject());
		if (i >= 0) {
			users.get(i).setState(Model.User.STATE_AVAILABLE);
		}

		return generateResult(lastUpdate);
	}

	@Override
	public void doUserBusy() {
		int i = users.indexOf(getUser().getEventObject());
		if (i >= 0) {
			users.get(i).setState(Model.User.STATE_BUSY);
		}
	}

	@Override
	public void doUserOffline() throws UnauthorizedException {
		int i = users.indexOf(getUser().getEventObject());
		if (i >= 0) {
			Model.User user = users.remove(i);
		}
	}

}
